// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include "FunctionInterfaceImpl.hpp"
#include "Exception.hpp"

using namespace ninf::lib;
using namespace std;
FunctionInterfaceImpl ::  FunctionInterfaceImpl(DataInputStream & dis){
  EBEGIN { versionMajor = dis.readInt();        } EEND 
  EBEGIN { versionMinor = dis.readInt();        } EEND 
  EBEGIN { moduleName   = dis.readString();     } EEND 
  EBEGIN { entryName    = dis.readString();     } EEND 
  EBEGIN { nParams      = dis.readInt();        } EEND 

  params = new ParamDesc * [nParams];

  for (int i = 0; i < nParams; i++){
    EBEGIN { params[i]  = new ParamDesc(dis); } EEND 
  }
  
  EBEGIN { description  = dis.readString();     } EEND 
  EBEGIN { shrink       = (bool) dis.readInt(); } EEND 
}

FunctionInterfaceImpl :: FunctionInterfaceImpl(
  int versionMajor,
  int versionMinor,
  const char * moduleName,
  const char * entryName,
  int  nParams,
  ParamDesc ** params,
  const char * description,
  bool shrink)
  :
  versionMajor(versionMajor),
  versionMinor(versionMinor),
  moduleName(moduleName),
  entryName(entryName),
  nParams(nParams),
  params(params),
  description(description),
  shrink(shrink) {}


void
FunctionInterfaceImpl :: writeTo(DataOutputStream & dos){
  EBEGIN { dos.writeInt(versionMajor);  } EEND 
  EBEGIN { dos.writeInt(versionMinor);  } EEND 
  EBEGIN { dos.writeString(moduleName); } EEND 
  EBEGIN { dos.writeString(entryName);  } EEND 
  EBEGIN { dos.writeInt(nParams);       } EEND 

  for (int i = 0; i < nParams; i++){
    EBEGIN { params[i]->writeTo(dos);    } EEND 
  }
  
  if (description == NULL)
    description = "";
  EBEGIN { dos.writeString(description);} EEND 
  EBEGIN { dos.writeInt((int)shrink);   } EEND 
}

#define PUTTAB(fp,tab)   { for (int i = 0; i < tab; i++) fprintf(fp, "\t");}

  /** write out declaration */
void
FunctionInterfaceImpl :: writeDeclaration(int tab, int index, FILE * fp){
  for (int i = 0; i < nParams; i++)
    params[i]->writeDeclaration(tab, index, i, fp);
  fprintf(fp, "\n");
  
  PUTTAB(fp,tab);
  fprintf(fp, "ParamDesc ** params_%d = new ParamDesc * [%d];",
	  index, nParams);
  fprintf(fp, "\n");

  for (int i = 0; i < nParams; i++){
    PUTTAB(fp,tab);
    fprintf(fp, "params_%d[%d] = &desc_%d_%d;", index, i, index, i);
    fprintf(fp, "\n");
  }
  fprintf(fp, "\n");

  PUTTAB(fp,tab);
  fprintf(fp, "FunctionInterfaceImpl func_%d(",  index);
  fprintf(fp, "\n");

  PUTTAB(fp,tab);
  fprintf(fp, "  %d, %d, \"%s\", \"%s\", %d, params_%d,",
	  versionMajor, versionMinor, moduleName, entryName,
	  nParams, index);
  fprintf(fp, "\n");
  PUTTAB(fp,tab);
  fprintf(fp, "  \"%s\",", description);
  fprintf(fp, "\n");
  PUTTAB(fp,tab);
  fprintf(fp, "  (bool)%d);", (int)shrink);
  fprintf(fp, "\n");
}

void 
FunctionInterfaceImpl :: setupArgs(va_list ap, Arg * args){
  // copy args to ArgArray
  for (int i = 0; i < nParams; i++)
    params[i]->setupArg(&ap, args+i);

  // setup iArgs
  int iArgs[nParams];
  for (int i = 0; i < nParams; i++)
    iArgs[i] = args[i].asInt();

  // setup Shape
  for (int i = 0; i < nParams; i++)
    args[i].setupShape(params[i], iArgs, nParams);
}

void
FunctionInterfaceImpl :: setupStubArgs(Arg * args){
  for (int i = 0; i < nParams; i++){
    args[i].dataType = params[i]->dataType;
    args[i].modeType = params[i]->modeType;
    args[i].nDim     = params[i]->nDim;
  }

  // setup iArgs
  int iArgs[nParams];
  for (int i = 0; i < nParams; i++)
    iArgs[i] = args[i].asInt();

  // setup Shape
  for (int i = 0; i < nParams; i++)
    args[i].setupShape(params[i], iArgs, nParams);
}
